#include "core_pch.h"
#include "RTTI.h"
#include "Res.h"
#include "Utility.h"
#include "DString.h"
#include "SString.h"
#include "RawBuf.h"

TMap< SString, Pack::Ptr> Pack::sPackMap;

void Pack::Load()
{
	mResList.Clear();
	mObjDatas.Clear();
	mInpackLinks.Clear();
	mOutpackLinks.Clear();
	mStreamObjList.Clear();

	ds_t fileName = (const char*)mName;
	fileName += ".pck";
	if( !Ogre::ResourceGroupManager::getSingletonPtr()->resourceExistsInAnyGroup( (const char*)fileName))
	{
		return;
	}

	mDataStream = Ogre::ResourceGroupManager::getSingletonPtr()
		->openResource( (const char*)fileName);

	mIsSaveing = false;

	s32_t ver = 0;
	_readRaw( &ver, sizeof(ver));
	_check( ver == 0);

	s32_t numObj = 0;
	_readRaw( &numObj, sizeof(numObj));

	for( s32_t i = 0 ; i < numObj; ++numObj)
	{
		mStreamObjList.Add( _readObj());
	}
	
	for( s32_t i = 0; i < mInpackLinks.Num(); ++i)
	{
		InpackLink& link = mInpackLinks[i];
		(*link.ObjPtr) = mStreamObjList[ link.LinkID];
	}

	mInpackLinks.Clear();
	mStreamObjList.Clear();

	mDataStream->close();
	mDataStream.setNull();
}

Obj* Pack::_readObj()
{
	bool isNull = false;
	_readRaw( &isNull, sizeof(isNull));
	if( isNull)
	{
		return 0;
	}

	ds_t clsName = _readString();
	ClassDef* clsDef = ClassDef::GetClass( clsName);
	_check( clsDef);

	Obj* readObj = 0;
	if( clsDef == Pack::RTTI())
	{
		readObj = this;
	}
	else
	{
		readObj = clsDef->New();
	}

	readObj->OnStream( this);

	// object super class list
	TArray< ClassDef* > clsList;
	clsDef->GetInheritClassList( clsList);

	TArray< ClassDef* >::Iterator inherIt( clsList);
	while( inherIt)
	{
		ClassDef* loadType = *inherIt;
		inherIt.Next();

		TArray< PropDef*>::Iterator dataIt = loadType->PropIt();
		while( dataIt)
		{
			PropDef* dataDef = *dataIt;
			dataIt.Next();

			PropData dataVal;
			readObj->GetMemberData( dataDef, dataVal);
			_readProp( dataVal);
		}
	}

	return readObj;
}

void Pack::_readProp( PropData& data)
{
	PropDef* def = data.Def;
	s32_t num = 1;
	if( def->IsArray)
	{
		_readRaw( &num, sizeof(num));
		data.SetArrayNum( num);
	}

	if( Data_SString == def->Type)
	{
		for( s32_t i = 0; i < num; ++i)
		{
			ss_t& str = *(ss_t*)data[i];
			str = _readString();
		}
	}
	else if( Data_DString == def->Type)
	{
		for( s32_t i = 0; i < num; ++i)
		{
			ds_t& str = *(ds_t*)data[i];
			str = _readString();
		}
	}
	else if( Data_Struct_Ins == def->Type)
	{
		for( s32_t i = 0; i < num; ++i)
		{
			void* stcPtr = data[i];

			StructDef* stcDef = def->StructType;
			_check( stcDef);

			for( s32_t p = 0; p < stcDef->Props.Num(); ++p)
			{
				PropData data;
				stcDef->GetMemberData( stcPtr, stcDef->Props[p], data);
				_readProp( data);
			}
		}
	}
	else if( Data_RefObj_Ptr == def->Type)
	{
		for( s32_t i = 0; i < num; ++i)
		{
			P(Obj)* objPtr = (P(Obj)*)data[i];
			s32_t linkIndex = null_index;
			_readRaw( &linkIndex, sizeof(linkIndex));

			if( linkIndex == null_index)// outpack res
			{
				OutpackResLink outLink;
				_readRaw( &outLink.ResIndex, sizeof( outLink.ResIndex));
				ds_t packName = _readString();

				P(Pack)* find = sPackMap.Find( (ss_t)packName);

				if( find == 0)
				{
					_check( false);
					continue;
				}
				outLink.OwnerPack = *find;

				outLink.ResPtr = (P(Res)*)objPtr;
				mOutpackLinks.Add( outLink);
			}
			else
			{
				InpackLink inpackLink;
				inpackLink.LinkID = linkIndex;
				inpackLink.ObjPtr = objPtr;
				mInpackLinks.Add( inpackLink);
			}
		}
	}
	else
	{
		if( num)
		{
			//raw array
			s32_t itemSize = RawTypeSize( def->Type);
			RawBuf& buf = *(RawBuf*)data.Data;
			_readRaw( buf.Data(), buf.Num() * itemSize);
		}
	}
}

void Pack::PostLoadLink()
{
	for( s32_t i = 0 ; i < mOutpackLinks.Num(); ++i)
	{
		OutpackResLink& link = mOutpackLinks[i];
		(*link.ResPtr) = link.OwnerPack->GetRes( link.ResIndex);
	}
}
